package cn.js189.redis;

import cn.hutool.json.JSONUtil;
import cn.js189.common.constants.ErrorConstants;
import cn.js189.common.util.exception.GlobalException;
import com.ctg.itrdc.cache.pool.CtgJedisPool;
import com.ctg.itrdc.cache.pool.CtgJedisPoolException;
import com.ctg.itrdc.cache.pool.ProxyJedis;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * redis工具类
 */
@Slf4j
@Component
public class RedisCache {

    private static final AtomicInteger connectionCount = new AtomicInteger(0);
    private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);

    private final CtgJedisPool ctgJedisPool;

    // ctg-redis 配置注入
    @Autowired
    public RedisCache(RedisConfig redisConfig) throws CtgJedisPoolException {
        this.ctgJedisPool = redisConfig.createCtgJedisPool();
        logger.info("{}",ctgJedisPool.getResource());
    }

    /**
     * 统计当前连接数
     * @return 连接数
     */
    public String nowCount(){
        String retStr = "now计数获取失败";
        try {
            int now = connectionCount.get();
            retStr = String.format("a.当前ctg-cache连接数：%s",now);
        }catch (Exception e){
            logger.error("a.now计数获取失败,"+e.getMessage(),e);
        }
        return retStr;
    }

    /**
     * 执行ctg-cache脚本获取到连接后计数
     * @param scriptName 脚本名称
     * @return 结果
     */
    public String openCount(String scriptName){
        String retStr = String.format("---b.[%s]open计数失败",scriptName);
        try {
            int open = connectionCount.addAndGet(1);
            retStr = String.format("---b.执行%s命令,打开一个新连接，当前连接数：%s",scriptName,open);
        }catch (Exception e){
            logger.error("open计数获取失败,"+e.getMessage(),e);
        }
        return retStr;

    }

    /**
     * 执行ctg-cache脚本命令完毕，关闭连接计数
     * @param scriptName 脚本名称
     * @return 结果
     */
    public String closeCount(String scriptName){
        String retStr = String.format("---c.[%s]close计数失败",scriptName);
        try {
            int close = connectionCount.addAndGet(-1);
            retStr = String.format("---c.执行:%s,命令完毕,关闭连接，当前连接数：%s",scriptName,close);
        }catch (Exception e){
            logger.error("close计数获取失败,"+e.getMessage(),e);
        }
        return retStr;
    }

    /**
     * 判断key是否存在
     */
    public boolean hasKey(String key)throws GlobalException {
        try (ProxyJedis jedis = ctgJedisPool.getResource()){
            return jedis.exists(key);
        } catch (CtgJedisPoolException e) {
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_CONN_ERROR);
        } catch (Exception e){
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException("ctg-cache执行失败");
        }
    }

    /**
     * 保存，长期有效
     */
    public String set(String key, Object value)throws GlobalException {
        String isTrue = "";
        try (ProxyJedis jedis = ctgJedisPool.getResource()) {
            if (JSONUtil.isTypeJSON(String.valueOf(value))) {
                isTrue = jedis.set(key, JSONUtil.toJsonStr(value));
            } else {
                isTrue = jedis.set(key, String.valueOf(value));
            }
            logger.info("插入缓存结果：{}", isTrue);
        } catch (CtgJedisPoolException e) {
            logger.error("{}", e.getMessage(), e);
            throw new GlobalException(ErrorConstants.REDIS_CONN_ERROR);
        } catch (Exception e) {
            logger.error("{}", e.getMessage(), e);
            throw new GlobalException(ErrorConstants.REDIS_SAVE_ERROR);
        }
        return isTrue;
    }

    /**
     * 获取 String 类型 key-value
     */
    public Object get(String key,Class<?> c)throws GlobalException {
        try(ProxyJedis jedis = ctgJedisPool.getResource()) {
            String value= jedis.get(key);
            if(StringUtils.isNotBlank(value)){
                if(c == String.class){
                    return value;
                }
                return new Gson().fromJson(value, c);
            }
            return null;
        } catch (CtgJedisPoolException e) {
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_CONN_ERROR);
        } catch (Exception e){
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException("ctg-cache获取对象失败");
        }
    }

    /**
     * 获取 String 类型 key-value
     */
    public String get(String key)throws GlobalException{
        try (ProxyJedis jedis = ctgJedisPool.getResource()){
            return jedis.get(key);
        } catch (CtgJedisPoolException e) {
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_CONN_ERROR);
        } catch (Exception e){
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException("ctg-cache获取字符串失败");
        }
    }

    /**
     * 设置 String 类型 key-value 并添加过期时间 (分钟单位)
     */
    public void setForTimeMin(String key, Object value, long time)throws GlobalException {
        try (ProxyJedis jedis = ctgJedisPool.getResource()){
            int seconds = Integer.parseInt(String.valueOf(time * 60L));
            if(JSONUtil.isTypeJSON(String.valueOf(value))){
                jedis.setex(key,seconds,new Gson().toJson(value));
            }else{
                jedis.setex(key,seconds,String.valueOf(value));
            }
        } catch (CtgJedisPoolException e) {
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_CONN_ERROR);
        } catch (Exception e){
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_SAVE_ERROR);
        }
    }

    /**
     * 设置 String 类型 key-value 并添加过期时间 (秒单位)
     */
    public void setForTimeMs(String key, Object value, long time)throws GlobalException {
        try(ProxyJedis jedis = ctgJedisPool.getResource()) {
            int seconds = Integer.parseInt(Long.toString(time));
            if(JSONUtil.isTypeJSON(String.valueOf(value))){
                jedis.setex(key,seconds,JSONUtil.toJsonStr(value));
            }else{
                jedis.setex(key,seconds,String.valueOf(value));
            }
        } catch (CtgJedisPoolException e) {
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_CONN_ERROR);
        } catch (Exception e){
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_SAVE_ERROR);
        }
    }


    /**
     * 设置 String 类型 key-value 并添加过期时间 (天单位)
     */
    public void setValueForDay(String key, Object value, long time)throws GlobalException {
        try (ProxyJedis jedis = ctgJedisPool.getResource()){
            long milliseconds = time * 24 * 60 * 60 * 1000;
            if(JSONUtil.isTypeJSON(String.valueOf(value))){
                jedis.set(key,JSONUtil.toJsonStr(value));
            }else{
                jedis.set(key,String.valueOf(value));
            }
            jedis.pexpire(key,milliseconds);
        } catch (CtgJedisPoolException e) {
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_CONN_ERROR);
        } catch (Exception e){
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_SAVE_ERROR);
        }
    }

    /**
     * 根据KEY删除数据
     */
    public void delete(String key)throws GlobalException {
        try(ProxyJedis jedis = ctgJedisPool.getResource()) {
            jedis.del(key);
        } catch (CtgJedisPoolException e) {
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_CONN_ERROR);
        } catch (Exception e){
            logger.error("{}",e.getMessage(),e);
            throw new GlobalException(ErrorConstants.REDIS_REMOVE_ERROR);
        }
    }
    
    /**
     * 缓存写入 包含重试机制 尝试三次写入
     * @param key 键
     * @param value 值
     * @return 结果
     */
    public boolean writeToRedis(String key, String value) {
        String redisDealResult = "";
        int retryCount = 0;
        while (retryCount < 3) {
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            try {
                redisDealResult = set(key, value);
                if ("OK".equalsIgnoreCase(redisDealResult)) {
                    return true;
                }
            } catch (Exception e) {
                log.error("redis缓存写入失败：{}, 重试次数: {}", e.getMessage(), retryCount, e);
            }
            retryCount++;
        }
        return false;
    }
}
